package p.ithorns.integration.hazelcast.mqtt;

import com.hazelcast.cluster.Endpoint;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IExecutorService;
import com.hazelcast.map.IMap;
import io.netty.buffer.ByteBuf;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import p.ithorns.framework.common.thread.SystemClock;
import p.ithorns.framework.common.utils.ByteUtil;

import java.io.Serializable;

@Slf4j
@Service
public class MqttUpDataRawHandler extends AbstractDataHandler<GateUp> {

    private final HazelcastInstance hz;

    private final IExecutorService executor;

    private final IMap<Object, Object> raw;

    private final Endpoint endpoint;

    public MqttUpDataRawHandler(HazelcastInstance hz) {
        this.hz = hz;
        this.executor = hz.getExecutorService("EXECUTOR");
        this.raw = hz.getMap("RAW");
        this.endpoint = hz.getLocalEndpoint();
    }

    @Override
    public Serializable getCode() {
        return Topics.Data.GATE_RAW;
    }

    @Override
    public void handle(GateUp upDataRaw) {
        Payload frame = resolveCard(upDataRaw);
        if (raw.tryLock(upDataRaw.getFcnt())) {
            try {
                executor.execute(new Task(frame));
            } catch (Exception e) {
                log.warn(e.getMessage());
            }
        } else {
            log.warn("[{}] 重复执行了: {}", endpoint.getSocketAddress(), frame);
        }
    }

    static class Task implements Runnable, Serializable {
        final Payload frame;

        public Task(Payload frame) {
            this.frame = frame;
        }

        @Override
        public void run() {
            DataHandler<Payload> handler = DataHandlerContext.get(frame.getCode());
            if (null != handler) {
                handler.handle(frame);
            }
        }
    }

    /**
     * 指令
     * 1个字节(8位表示)
     * 0  : 指令(1bit)
     * - 0:up
     * - 1:down
     * <p>
     * 1~3: 主类型(3bit)
     * - 1:定位数据
     * - 2:状态事件
     * - 3:设备配置
     * <p>
     * 4~7: 子类型
     * 1-0: beacon_data, 直接使用beaconRaws
     * 2-0: sos
     * 2-1: sos_exit
     * 2-2: dev_sleep
     * 2-3: dev_wake_up
     * 3-0: ble_config
     * 3-1: lora_config
     */
    private Payload resolveCard(GateUp upDataRaw) {
        String data = Encryption.hexEncrypt(upDataRaw.getData());
        byte[] bytes = ByteUtil.hexStr2Bytes(data);

        // 分配byte缓冲区
        ByteBuf buffer = DataHandlerContext.getAllocator().buffer(bytes.length);
        buffer.writeBytes(bytes);

        // 获取处理类型
        byte cmdBit = buffer.readByte();

        String cardId = String.format("%08X", upDataRaw.getCardId());

        // 指令类型
        int cmdCode = ByteUtil.getBitsLE(cmdBit, 0, 4);
        UpMsgType type = UpMsgType.of(cmdCode);

        // 释放byte缓冲区
        ReferenceCountUtil.release(buffer);

        int fcnt = upDataRaw.getFcnt();

        return Payload.builder()
                .code(type)
                .devId(cardId)
                .seq(fcnt)
                .timestamp(SystemClock.now())
                .raw(bytes)
                .build();
    }

}